package cn.humaohua.study.yanmo_design_pattern.ch20.v2;

import java.util.*;
import java.util.concurrent.TimeUnit;

public class FlyweightFactory {
    private static FlyweightFactory flyweightFactory = new FlyweightFactory();
    //缓存过期时间
    private static final long DURABLE_TIME_IN_MS = 6 * 1000L;

    //缓存的享元对象
    private Map<String, Flyweight> map = new HashMap<>();
    //缓存开始时间
    private Map<String, CacheConfModel> cacheTimeMap = new HashMap<>();
    //引用计数
    private Map<String, Integer> cacheCountMap = new HashMap<>();

    private FlyweightFactory() {
        new Thread(new ClearCache()).start();
    }

    public static FlyweightFactory getInstance() {
        return flyweightFactory;
    }

    public synchronized Flyweight getFlyweight(String key) {
        Flyweight flyweight = map.get(key);
        if (flyweight == null) {
            String[] arr = key.split(",");
            flyweight = new AuthorizationFlyweight(arr[0] + "," + arr[1]);
            map.put(key, flyweight);

            //设置缓存配置
            CacheConfModel cacheConfModel = new CacheConfModel();
            cacheConfModel.setForever(false);
            cacheConfModel.setDurableTime(DURABLE_TIME_IN_MS);
            cacheConfModel.setStartTime(System.currentTimeMillis());
            cacheTimeMap.put(key, cacheConfModel);

            //设置引用计数
            cacheCountMap.put(key, 1);

        } else {
            //更新缓存配置时间
            cacheTimeMap.get(key).setStartTime(System.currentTimeMillis());
            //引用计数加1
            cacheCountMap.put(key, cacheCountMap.get(key) + 1);
        }


        return flyweight;
    }

    public synchronized Integer getUseTimes(String key) {
        Integer count = cacheCountMap.get(key);
        if (count == null)
            count = 0;
        return count;
    }

    private synchronized void removeCache(String key) {
        System.out.println("remove cache key=" + key);
        map.remove(key);
        cacheTimeMap.remove(key);
        cacheCountMap.remove(key);
    }

    //缓存清理线程
    private class ClearCache implements Runnable {
        @Override
        public void run() {
            while (true) {
                System.out.println("clear thread is running");
                Set<String> set = map.keySet();
                Set<String> tmpSet = new HashSet<>();
                //先遍历出需要删除的key
                for (String key : set) {
                    CacheConfModel cacheConfModel = cacheTimeMap.get(key);
                    //如果缓存永久有效
                    if (cacheConfModel.isForever())
                        continue;
//                        Integer count = getUseTimes(key);
//                        //对象被引用
//                        if (count > 0)
//                            continue;
                    //如果缓存过期
                    if (new Date().getTime() - cacheConfModel.getStartTime() >= cacheConfModel.getDurableTime()) {
                        tmpSet.add(key);
                    }
                }
                //对要删除的key，进行清除缓存
                //重要技巧，由于没有在遍历时清除map对象，避免了普通map并发修改异常
                for (String key : tmpSet) {
                    removeCache(key);
                }
                try {
                    System.out.println("clear over, sleep 1 second");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
